#include <iostream>
#include "rrtracer.h"
#include <stdint.h>
#include "rrscreenmapping.h"
#include <SDL_image.h>
#include <SDL_endian.h>

using namespace std;

SDL_Surface *screen = NULL;
SDL_Surface *backscreen = NULL;
SDL_Surface *background_image = NULL;

RRTracer tracer;
RRScreenMapping mapping;

void Update(void)
{
    /* here to code processes to update the state */
}

void DrawPixel(SDL_Surface *screen)
{
    //Uint32 color = SDL_MapRGB(screen->format, R, G, B);

    if(SDL_MUSTLOCK(screen)) {
        if(SDL_LockSurface(screen) < 0) {
            return;
        }
    }

    float xs, ys;
    for(int i=0; i<640; i++)
        for(int j=0; j<480; j++) {
            Uint32 *bufp;
            Uint32 color;
            mapping.rrScreenMapping(i, j, &xs, &ys);
            bufp = (Uint32 *)screen->pixels + j*screen->pitch/4 + i;
            RRVec4 c = tracer.rrEmitRay(xs, ys);
            color = SDL_MapRGB(screen->format, (int)255 * c.x, (int)255 * c.y, (int)255 * c.z);
            *bufp = color;
        }

    if(SDL_MUSTLOCK(screen)) {
        SDL_UnlockSurface(screen);
    }
}

void Draw(void)
{
    /* here to code drawing processes  */
    DrawPixel(backscreen);

    // update screen
    SDL_BlitSurface(backscreen, NULL, screen, NULL);
    SDL_Flip(screen);
}

int Initialize(void)
{
    RRVec4 clr = RRSetVec4(0.6, 0.6, 1.0, 1.0);
    RRVec3 sz = RRSetVec3(0.0, -50.0, 0.0);
    RRVec3 crd = RRSetVec3(0.0, -24.0, 0.0);
    RRMaterial material;
    material.rrSetMaterial(0.0, 0.0, -1, clr, clr, 1.0);
    RRPlane plane; RRQuadric quadric; RRCuboid cuboid;
    plane.rrSetPrim(sz, sz);

    //wall
    tracer.rrBeginObject();

    tracer.rrBeginComponent(&material);
    tracer.rrSetPrim(&plane);
    tracer.rrEndComponent();

    tracer.rrBeginComponent(&material);
    sz = RRSetVec3(0.0, 20.0, 0.0); plane.rrSetPrim(sz, sz);
    tracer.rrSetPrim(&plane);
    tracer.rrEndComponent();

    clr = RRSetVec4(1.0, 0.0, 0.0, 1.0);
    material.rrSetMaterial(0.0, 0.0, -1, clr, clr, 1.0);
    tracer.rrBeginComponent(&material);
    sz = RRSetVec3(0.0, 0.0, -50.0); plane.rrSetPrim(sz, sz);
    tracer.rrSetPrim(&plane);
    tracer.rrEndComponent();

    tracer.rrEndObject();

    //dice
    tracer.rrBeginObject();

    clr = RRSetVec4(0.3, 0.3, 1.0, 1.0);
    material.rrSetMaterial(0.6, 0.0, 1, clr, clr, 1.0);
    tracer.rrBeginComponent(&material);
    sz = RRSetVec3(8.0, 8.0, 8.0);
    crd = RRSetVec3(-0.0, 16.0, -0.0);
    cuboid.rrSetPrim(sz, crd);
    tracer.rrSetPrim(&cuboid);

    sz = RRSetVec3(5.0, 5.0, 5.0);
    quadric.rrSetPrim(sz, crd);
    tracer.rrSetPrim(&quadric);
    tracer.rrEndComponent();

    tracer.rrEndObject();

    tracer.rrBeginObject();

    tracer.rrBeginComponent(&material);
    sz = RRSetVec3(2.0, -8.0, 2.0);
    crd = RRSetVec3(-35.0, -30.0, 10.0);
    quadric.rrSetPrim(sz, crd, -40.0 / 180.0 * 3.14159);
    tracer.rrSetPrim(&quadric);
    tracer.rrEndComponent();

    tracer.rrBeginComponent(&material);
    sz = RRSetVec3(2.0, -10.0, 2.0);
    crd = RRSetVec3(35.0, -10.0, 0.0);
    quadric.rrSetPrim(sz, crd, 40.0 / 180.0 * 3.14159);
    tracer.rrSetPrim(&quadric);
    tracer.rrEndComponent();

    tracer.rrEndObject();

    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0) {
        fprintf(stderr, "failed to initialize SDL: %s\n", SDL_GetError());
        return -1;
    }

    SDL_WM_SetCaption("My SDL Sample", NULL);

    screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE | SDL_DOUBLEBUF);

    backscreen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);

    if(screen == NULL) {
        fprintf(stderr, "failed to initialize the screen: %s\n", SDL_GetError());
        SDL_Quit();
        return -1;
    }

    return 0;
}

void MainLoop(void)
{
    SDL_Event event;
    //double next_frame = SDL_GetTicks();
    double current_time;
    double elapsed_time = 0.0;
    double prev_time = 0.0;
    //double wait = 1000.0 / 60;
    int frame_cnt = 0;
    double fps = 0.0;

    while(1) {
        /* deal with all events */
        while(SDL_PollEvent(&event)) {
            if((event.type == SDL_QUIT) || (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE)) {
                //puts("Im dealing with SDL_QUIT");
                return;
            }
        }
        //        if(SDL_GetTicks() >= next_frame) {
        //            //puts("Im dealing with Update");
        Update();
        //            if(SDL_GetTicks() < next_frame + wait) {
        //                //puts("im dealing with Draw");
        Draw();
        //            }
        //            next_frame += wait;
        SDL_Delay(0);
        //        }
        frame_cnt++;
        if(frame_cnt >= 5) {
            current_time = SDL_GetTicks();
            elapsed_time = current_time - prev_time;
            fps = 1000.0 * 5.0 / elapsed_time;
            frame_cnt = 0;
            prev_time = current_time;
            printf("%ffps\n", fps);
        }
    }
}

void Finalize(void)
{
    /* here to free images and sounds */

    SDL_Quit();
}

int main(int argc, char *argv[])
{
    if(Initialize() < 0)
        return -1;

    MainLoop();

    Finalize();

    return 0;
}

